/*
//
//                  INTEL CORPORATION PROPRIETARY INFORMATION
//     This software is supplied under the terms of a license agreement or
//     nondisclosure agreement with Intel Corporation and may not be copied
//     or disclosed except in accordance with the terms of that agreement.
//          Copyright(c) 2003-2007 Intel Corporation. All Rights Reserved.
//
//     Intel Integrated Performance Primitives AAC Encode Sample for Windows*
//
//  By downloading and installing this sample, you hereby agree that the
//  accompanying Materials are being provided to you under the terms and
//  conditions of the End User License Agreement for the Intel Integrated
//  Performance Primitives product previously accepted by you. Please refer
//  to the file ippEULA.rtf or ippEULA.txt located in the root directory of your Intel IPP
//  product installation for more information.
//
//  MPEG-4 and AAC are international standards promoted by ISO, IEC, ITU, ETSI
//  and other organizations. Implementations of these standards, or the standard
//  enabled platforms may require licenses from various entities, including
//  Intel Corporation.
//
*/

#include "umc_defs.h"
#if defined (UMC_ENABLE_MP3_INT_AUDIO_ENCODER)

#include "mp3enc_own_int.h"

#define  N_SHORT 256
#define  N_LONG 1024

/****************************************************************************/

typedef struct _ptbl_s {
  Ipp16s numlines;
  Ipp32s qthr;
  Ipp32s SNR;
  Ipp16s bval;
} ptbl_s;

typedef struct _p2sb {
  Ipp32s bu;
  Ipp32s bo;
  Ipp32s w1;
  Ipp32s w2;
} p2sb;

static const p2sb mp3ienc_p2sb_l[3][SBBND_L] = {
 { /* freq = 44100 */
  { 0,  4, 536870911,  30064771},
  { 4,  7, 506806143, 328028127},
  { 7, 11, 208842783,  89657439},
  {11, 14, 447213471, 387620799},
  {14, 17, 149250111,  74625055},
  {17, 18, 462245855, 492310623},
  {18, 21,  44560283, 312995743},
  {21, 24, 223875167, 134217727},
  {24, 27, 402653183, 432181087},
  {27, 30, 104152959, 308163903},
  {30, 33, 228707007, 288299679},
  {33, 36, 248571231, 439697279},
  {36, 40,  96636767,  53687091},
  {40, 43, 483183807, 251255583},
  {43, 46, 285615327, 334470591},
  {46, 49, 201863455, 241591903},
  {49, 52, 295279007, 296352735},
  {52, 55, 240518175, 216358975},
  {55, 57, 320511935, 345207999},
  {57, 59, 191662911, 387620799},
  {59, 61, 149250111, 515396063},
 },
 { /* freq = 48000 */
  { 0,  4, 536870911,  30064771},
  { 4,  7, 506806143, 328028127},
  { 7, 11, 208842783,  89657439},
  {11, 14, 447213471, 387620799},
  {14, 17, 149250111, 343060511},
  {17, 19, 193810399, 223875167},
  {19, 22, 312995743,  44560283},
  {22, 24, 492310623, 402653183},
  {24, 27, 134217727, 223875167},
  {27, 30, 312995743, 347892351},
  {30, 33, 188978559, 328028127},
  {33, 36, 208842783, 335544319},
  {36, 40, 201326591,  77309407},
  {40, 43, 459561503, 208842783},
  {43, 46, 328028127,  85899343},
  {46, 49, 450971551, 116500983},
  {49, 52, 420369919,  98784247},
  {52, 54, 438086655, 475667615},
  {54, 57,  61203283, 168040591},
  {57, 59, 368830303, 242665647},
  {59, 60, 294205247, 487478783},
 },
 { /* freq = 32000 */
  { 0,  2, 536870911, 283467839},
  { 2,  4, 253403071, 163745631},
  { 4,  6, 372588415,  44560283},
  { 6,  7, 492310623, 462245855},
  { 7,  9,  74625055, 343060511},
  { 9, 11, 193810399, 223875167},
  {11, 14, 312995743,  44560283},
  {14, 16, 492310623, 402653183},
  {16, 19, 134217727, 467077695},
  {19, 22,  69793215, 447213471},
  {22, 26,  89657439, 208842783},
  {26, 30, 328028127, 256624287},
  {30, 34, 280246623,  17716739},
  {34, 37, 519154175, 492310623},
  {37, 41,  44560283, 331249343},
  {41, 44, 205621551, 534186559},
  {44, 48,   2684354, 147102623},
  {48, 51, 389768287, 257698031},
  {51, 54, 278635999, 140123311},
  {54, 56, 396747615, 474593887},
  {56, 58,  62277023, 536870911},
 }
};

static const p2sb mp3ienc_p2sb_s[3][SBBND_S] = {
 { /* freq = 44100 */
  { 0,  2, 536870911,  89657439},
  { 3,  5, 447213471, 447213471},
  { 5,  8,  89657439, 268435455},
  { 8, 11, 268435455,  89657439},
  {11, 15, 447213471,  89657439},
  {15, 20, 447213471, 134217727},
  {20, 23, 402653183, 312995743},
  {23, 27, 223875167,  29527899},
  {27, 30, 506806143, 201326591},
  {30, 33, 335544319, 161061279},
  {33, 36, 375809631,  89657439},
  {36, 38, 447213471, 536870911},
 },
 { /* freq = 48000 */
  { 0,  2, 536870911,  89657439},
  { 3,  5, 447213471, 447213471},
  { 5,  8,  89657439, 268435455},
  { 8, 11, 268435455,  89657439},
  {11, 15, 447213471,  89657439},
  {15, 19, 447213471, 312995743},
  {19, 22, 223875167, 492310623},
  {22, 26,  44560283, 506806143},
  {26, 30,  29527899,  22548577},
  {30, 32, 514322335, 304405791},
  {32, 35, 232465103,  89657439},
  {35, 37, 447213471, 331786207},
 },
 { /* freq = 32000 */
  { 0,  2, 536870911,  89657439},
  { 3,  5, 447213471, 447213471},
  { 5,  8,  89657439, 268435455},
  { 8, 11, 268435455,  89657439},
  {11, 15, 447213471,  89657439},
  {15, 20, 447213471, 134217727},
  {20, 24, 402653183, 134217727},
  {24, 29, 402653183,  29527899},
  {29, 33, 506806143, 201326591},
  {33, 37, 335544319, 253403071},
  {37, 40, 283467839, 503048031},
  {40, 41,  33285995, 536870911},
 },
};

static const ptbl_s mp3ienc_ptbl_s[3][CBANDS_s] = {
 { /* freq = 44100 */
  { 1,  148504, 644109759,      0},
  { 1,   29622, 633159871,   1762},
  { 1,     950, 633159871,   3524},
  { 1,     294, 632515775,   5173},
  { 1,     294, 634448063,   6569},
  { 1,     294, 633159871,   7784},
  { 1,     294, 629939327,   8910},
  { 1,     294, 622854143,   9884},
  { 1,     294, 610615999,  10756},
  { 1,     294, 599022079,  11552},
  { 1,     294, 706652735,  12285},
  { 1,     294, 672634431,  12915},
  { 1,     294, 653305855,  13513},
  { 1,     294, 618514431,  14064},
  { 1,     294, 579084159,  14568},
  { 1,     294, 541973311,  15032},
  { 1,     294, 504862431,  15472},
  { 1,     294, 456154399,  15864},
  { 1,     294, 476256127,  16256},
  { 2,     589, 664903039,  16917},
  { 2,     589, 706902783,  17505},
  { 2,     589, 654507775,  18026},
  { 2,     589, 590946687,  18488},
  { 2,     589, 525667679,  18894},
  { 2,     589, 510206879,  19282},
  { 3,     884, 565178687,  19714},
  { 3,     884, 606407487,  20195},
  { 3,    1769, 566896511,  20641},
  { 3,    1769, 520514079,  21049},
  { 3,    1769, 485297791,  21431},
  { 4,    3735, 601378495,  21806},
  { 4,    3735, 621782399,  22198},
  { 5,   14811, 608895743,  22585},
  { 5,   14811, 573457343,  22954},
  { 5,   14811, 662251519,  23305},
  { 7,  207421, 669982079,  23665},
  { 7,  207421, 667405247,  24024},
  { 7,  207421, 653232575,  24376},
  {19, 5629968, 671997055,  24728},
 },
 { /* freq = 48000 38 */
  { 1,  148504, 644109759,      0},
  { 1,   29622, 637024511,   1918},
  { 1,     950, 637024511,   3836},
  { 1,     294, 631871615,   5563},
  { 1,     294, 634448063,   7014},
  { 1,     294, 633803967,   8295},
  { 1,     294, 631227519,   9449},
  { 1,     294, 623498239,  10436},
  { 1,     294, 614480703,  11337},
  { 1,     294, 598377919,  12137},
  { 1,     294, 700467583,  12842},
  { 1,     294, 682685311,  13498},
  { 1,     294, 652532735,  14097},
  { 1,     294, 612329279,  14638},
  { 1,     294, 577537855,  15143},
  { 1,     294, 532695583,  15600},
  { 1,     294, 497904127,  16027},
  { 1,     294, 457700703,  16437},
  { 1,     294, 427548095,  16786},
  { 2,     589, 657171583,  17437},
  { 2,     589, 696595583,  18011},
  { 2,     589, 632175551,  18513},
  { 2,     589, 571191167,  18954},
  { 2,     589, 523949823,  19366},
  { 2,     589, 467260159,  19738},
  { 2,     589, 453517215,  20087},
  { 3,    1769, 533398079,  20498},
  { 3,    1769, 578062655,  20957},
  { 3,    1769, 545423167,  21380},
  { 4,    3735, 537692735,  21796},
  { 4,    3735, 682994111,  22221},
  { 5,   14811, 660442431,  22636},
  { 5,   14811, 621782399,  23030},
  { 5,   14811, 591713471,  23403},
  { 7,  207421, 711211775,  23775},
  { 7,  207421, 720230783,  24159},
  {11,  325943, 680289535,  24525},
  {17, 5037326, 617156607,  24872},
 },
 { /* freq = 32000 */
  { 1,  148504, 644109759,      0},
  { 1,   29622, 634448063,   1278},
  { 1,    2949, 633159871,   2557},
  { 1,     950, 633159871,   3836},
  { 1,     294, 631871615,   5021},
  { 1,     294, 628006975,   6095},
  { 1,     294, 617701247,   7014},
  { 1,     294, 608039615,   7877},
  { 1,     294, 600954367,   8695},
  { 1,     294, 592580927,   9449},
  { 1,     294, 689643583,  10122},
  { 1,     294, 667222463,  10741},
  { 1,     294, 648667007,  11337},
  { 1,     294, 607690431,  11870},
  { 1,     294, 583723007,  12385},
  { 1,     294, 539653823,  12842},
  { 1,     294, 520325279,  13299},
  { 1,     294, 467751551,  13698},
  { 1,     294, 486306975,  14097},
  { 2,     589, 682685311,  14806},
  { 2,     589, 736965503,  15443},
  { 2,     589, 712056383,  16027},
  { 2,     589, 658802495,  16549},
  { 2,     589, 605548543,  17018},
  { 2,     589, 547141055,  17449},
  { 2,     589, 484438847,  17829},
  { 2,     589, 472413759,  18195},
  { 3,     884, 517937279,  18595},
  { 3,     884, 545423167,  19024},
  { 3,     884, 508488991,  19430},
  { 3,     884, 572383423,  19797},
  { 3,     884, 556275071,  20145},
  { 4,    2359, 609969599,  20527},
  { 4,    2359, 637890751,  20932},
  { 4,    2359, 731826623,  21320},
  { 5,    4685, 690596927,  21688},
  { 5,    4685, 672558975,  22044},
  { 6,    5636, 698327487,  22414},
  { 7,   20742, 810305215,  22787},
  { 7,   20742, 780238207,  23145},
  { 8,   23691, 882923327,  23499},
  {10,  296321, 889794303,  23857},
 },
};

/****************************************************************************/

static const Ipp16s mp3ienc_pa_numlines_l[3][CBANDS_l] = {
    {
        1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,   2,
        2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,   3,   3,   4,
        4,   4,   5,   5,   5,   6,   6,   7,   7,   7,   9,   9,   9,  10,  10,  11,  14,  14,
        15,  20,  20,  21,  27,  27,  36,  73,  18, /* {47,*/
    },
    {
        1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,
        2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,   4,   4,
        4,   4,   4,   5,   5,   5,   6,   7,   7,   8,   8,   8,  10,  10,  10,  13,  13,  14,
        18,  18, 20,  25,  25,  35,  67,  67,
    },
    {
        2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,   2,
        3,   3,   3,   3,   3,   3,   3,   3,   3,   4,   4,   4,   5,   5,   5,   5,   5,   6,
        6,   6,   8,   8,   8,  10,  10,  10,  12,  12,  13,  14,  14,  16,  20,  20,  23,  27,
        27,  32,  37,  37,  12,  24,
    }
};

static const Ipp16s mp3ienc_bval_l[3][CBANDS_l] = {
    {
        0, 441, 881, 1323, 1764, 2204, 2646, 3087, 3527, 3969, 4381, 4782,
        5178, 5545, 5912, 6576, 7194, 7791, 8364, 8919, 9427, 9893, 10341,
        10767, 11179, 11564, 11931, 12284, 12691, 13158, 13595, 14009, 14399,
        14756, 15105, 15481, 15880, 16264, 16653, 17053, 17428, 17790, 18169,
        18538, 18889, 19232, 19589, 19954, 20314, 20663, 21002, 21352, 21704,
        22047, 22394, 22747, 23099, 23447, 23789, 24129, 24470, 24810, 25028,
    },
    {
        0, 480, 960, 1439, 1920, 2400, 2880, 3359, 3840, 4299, 4736, 5168, 5568,
        5967, 6336, 6678, 7346, 7988, 8603, 9181, 9711, 10205, 10676, 11126, 11549,
        11949, 12331, 12683, 13026, 13429, 13887, 14319, 14715, 15094, 15503, 15936,
        16345, 16715, 17064, 17428, 17789, 18132, 18478, 18839, 19212, 19578, 19933,
        20282, 20642, 21014, 21374, 21723, 22070, 22417, 22764, 23110, 23458, 23805,
        24148, 24488, 24827, 25165, 0,
    },
    {
        320, 960, 1600, 2240, 2880, 3520, 4142, 4736, 5297, 5834, 6333, 6793, 7239,
        7671, 8094, 8504, 8903, 9281, 9711, 10205, 10676, 11126, 11549, 11949, 12331,
        12683, 13026, 13405, 13811, 14205, 14610, 15031, 15428, 15794, 16149, 16506,
        16861, 17210, 17569, 17938, 18297, 18652, 19008, 19355, 19700, 20049, 20403,
        20755, 21100, 21446, 21798, 22154, 22507, 22854, 23199, 23544, 23885, 24223,
        24511, 24818, 0, 0, 0,
    },
};

static const Ipp16s ipa_hann_window_long[1024] = {
    0, 0, 1, 3, 6, 9, 13, 17, 22, 27, 33, 40, 48, 56, 64, 74,
    83, 94, 105, 117, 129, 142, 155, 170, 184, 200, 216, 232, 249, 267, 286, 305,
    324, 344, 365, 387, 409, 431, 455, 478, 503, 528, 553, 580, 606, 634, 662, 690,
    720, 749, 780, 811, 842, 874, 907, 940, 974, 1009, 1044, 1079, 1116, 1152, 1190, 1227,
    1266, 1305, 1345, 1385, 1426, 1467, 1509, 1551, 1594, 1638, 1682, 1726, 1772, 1817, 1864, 1910,
    1958, 2006, 2054, 2103, 2153, 2203, 2254, 2305, 2356, 2409, 2461, 2515, 2568, 2623, 2678, 2733,
    2789, 2845, 2902, 2959, 3017, 3076, 3134, 3194, 3254, 3314, 3375, 3436, 3498, 3561, 3623, 3687,
    3750, 3815, 3879, 3945, 4010, 4076, 4143, 4210, 4278, 4346, 4414, 4483, 4552, 4622, 4692, 4763,
    4834, 4905, 4977, 5050, 5123, 5196, 5269, 5343, 5418, 5493, 5568, 5644, 5720, 5797, 5873, 5951,
    6029, 6107, 6185, 6264, 6343, 6423, 6503, 6583, 6664, 6745, 6827, 6908, 6991, 7073, 7156, 7239,
    7323, 7407, 7491, 7576, 7661, 7746, 7831, 7917, 8004, 8090, 8177, 8264, 8352, 8439, 8527, 8616,
    8705, 8793, 8883, 8972, 9062, 9152, 9242, 9333, 9424, 9515, 9606, 9698, 9790, 9882, 9975, 10067,
    10160, 10253, 10347, 10440, 10534, 10628, 10722, 10817, 10911, 11006, 11101, 11196, 11292, 11388, 11483, 11579,
    11676, 11772, 11869, 11965, 12062, 12159, 12256, 12354, 12451, 12549, 12647, 12745, 12843, 12941, 13039, 13138,
    13236, 13335, 13434, 13533, 13632, 13731, 13830, 13930, 14029, 14129, 14228, 14328, 14428, 14528, 14628, 14728,
    14828, 14928, 15028, 15128, 15228, 15329, 15429, 15529, 15630, 15730, 15831, 15931, 16032, 16132, 16233, 16333,
    16434, 16534, 16635, 16735, 16836, 16936, 17037, 17137, 17238, 17338, 17438, 17539, 17639, 17739, 17839, 17939,
    18039, 18139, 18239, 18339, 18439, 18539, 18638, 18738, 18837, 18937, 19036, 19135, 19234, 19333, 19432, 19531,
    19629, 19728, 19826, 19924, 20022, 20120, 20218, 20316, 20413, 20511, 20608, 20705, 20802, 20898, 20995, 21091,
    21188, 21284, 21379, 21475, 21571, 21666, 21761, 21856, 21950, 22045, 22139, 22233, 22327, 22420, 22514, 22607,
    22700, 22792, 22885, 22977, 23069, 23161, 23252, 23343, 23434, 23525, 23615, 23705, 23795, 23884, 23974, 24062,
    24151, 24240, 24328, 24415, 24503, 24590, 24677, 24763, 24850, 24936, 25021, 25106, 25191, 25276, 25360, 25444,
    25528, 25611, 25694, 25776, 25859, 25940, 26022, 26103, 26184, 26264, 26344, 26424, 26503, 26582, 26660, 26738,
    26816, 26894, 26970, 27047, 27123, 27199, 27274, 27349, 27424, 27498, 27571, 27644, 27717, 27790, 27862, 27933,
    28004, 28075, 28145, 28215, 28284, 28353, 28421, 28489, 28557, 28624, 28691, 28757, 28822, 28888, 28952, 29017,
    29080, 29144, 29206, 29269, 29331, 29392, 29453, 29513, 29573, 29633, 29691, 29750, 29808, 29865, 29922, 29978,
    30034, 30089, 30144, 30199, 30252, 30306, 30358, 30411, 30462, 30513, 30564, 30614, 30664, 30713, 30761, 30809,
    30857, 30903, 30950, 30995, 31041, 31085, 31129, 31173, 31216, 31258, 31300, 31341, 31382, 31422, 31462, 31501,
    31540, 31577, 31615, 31651, 31688, 31723, 31758, 31793, 31827, 31860, 31893, 31925, 31956, 31987, 32018, 32047,
    32077, 32105, 32133, 32161, 32187, 32214, 32239, 32264, 32289, 32312, 32336, 32358, 32380, 32402, 32423, 32443,
    32462, 32481, 32500, 32518, 32535, 32551, 32567, 32583, 32597, 32612, 32625, 32638, 32650, 32662, 32673, 32684,
    32693, 32703, 32711, 32719, 32727, 32734, 32740, 32745, 32750, 32754, 32758, 32761, 32764, 32766, 32767, 32767,
    32767, 32767, 32766, 32764, 32761, 32758, 32754, 32750, 32745, 32740, 32734, 32727, 32719, 32711, 32703, 32693,
    32684, 32673, 32662, 32650, 32638, 32625, 32612, 32597, 32583, 32567, 32551, 32535, 32518, 32500, 32481, 32462,
    32443, 32423, 32402, 32380, 32358, 32336, 32312, 32289, 32264, 32239, 32214, 32187, 32161, 32133, 32105, 32077,
    32047, 32018, 31987, 31956, 31925, 31893, 31860, 31827, 31793, 31758, 31723, 31688, 31651, 31615, 31577, 31540,
    31501, 31462, 31422, 31382, 31341, 31300, 31258, 31216, 31173, 31129, 31085, 31041, 30995, 30950, 30903, 30857,
    30809, 30761, 30713, 30664, 30614, 30564, 30513, 30462, 30411, 30358, 30306, 30252, 30199, 30144, 30089, 30034,
    29978, 29922, 29865, 29808, 29750, 29691, 29633, 29573, 29513, 29453, 29392, 29331, 29269, 29206, 29144, 29080,
    29017, 28952, 28888, 28822, 28757, 28691, 28624, 28557, 28489, 28421, 28353, 28284, 28215, 28145, 28075, 28004,
    27933, 27862, 27790, 27717, 27644, 27571, 27498, 27424, 27349, 27274, 27199, 27123, 27047, 26970, 26894, 26816,
    26738, 26660, 26582, 26503, 26424, 26344, 26264, 26184, 26103, 26022, 25940, 25859, 25776, 25694, 25611, 25528,
    25444, 25360, 25276, 25191, 25106, 25021, 24936, 24850, 24763, 24677, 24590, 24503, 24415, 24328, 24240, 24151,
    24062, 23974, 23884, 23795, 23705, 23615, 23525, 23434, 23343, 23252, 23161, 23069, 22977, 22885, 22792, 22700,
    22607, 22514, 22420, 22327, 22233, 22139, 22045, 21950, 21856, 21761, 21666, 21571, 21475, 21379, 21284, 21188,
    21091, 20995, 20898, 20802, 20705, 20608, 20511, 20413, 20316, 20218, 20120, 20022, 19924, 19826, 19728, 19629,
    19531, 19432, 19333, 19234, 19135, 19036, 18937, 18837, 18738, 18638, 18539, 18439, 18339, 18239, 18139, 18039,
    17939, 17839, 17739, 17639, 17539, 17438, 17338, 17238, 17137, 17037, 16936, 16836, 16735, 16635, 16534, 16434,
    16333, 16233, 16132, 16032, 15931, 15831, 15730, 15630, 15529, 15429, 15329, 15228, 15128, 15028, 14928, 14828,
    14728, 14628, 14528, 14428, 14328, 14228, 14129, 14029, 13930, 13830, 13731, 13632, 13533, 13434, 13335, 13236,
    13138, 13039, 12941, 12843, 12745, 12647, 12549, 12451, 12354, 12256, 12159, 12062, 11965, 11869, 11772, 11676,
    11579, 11483, 11388, 11292, 11196, 11101, 11006, 10911, 10817, 10722, 10628, 10534, 10440, 10347, 10253, 10160,
    10067, 9975, 9882, 9790, 9698, 9606, 9515, 9424, 9333, 9242, 9152, 9062, 8972, 8883, 8793, 8705,
    8616, 8527, 8439, 8352, 8264, 8177, 8090, 8004, 7917, 7831, 7746, 7661, 7576, 7491, 7407, 7323,
    7239, 7156, 7073, 6991, 6908, 6827, 6745, 6664, 6583, 6503, 6423, 6343, 6264, 6185, 6107, 6029,
    5951, 5873, 5797, 5720, 5644, 5568, 5493, 5418, 5343, 5269, 5196, 5123, 5050, 4977, 4905, 4834,
    4763, 4692, 4622, 4552, 4483, 4414, 4346, 4278, 4210, 4143, 4076, 4010, 3945, 3879, 3815, 3750,
    3687, 3623, 3561, 3498, 3436, 3375, 3314, 3254, 3194, 3134, 3076, 3017, 2959, 2902, 2845, 2789,
    2733, 2678, 2623, 2568, 2515, 2461, 2409, 2356, 2305, 2254, 2203, 2153, 2103, 2054, 2006, 1958,
    1910, 1864, 1817, 1772, 1726, 1682, 1638, 1594, 1551, 1509, 1467, 1426, 1385, 1345, 1305, 1266,
    1227, 1190, 1152, 1116, 1079, 1044, 1009, 974, 940, 907, 874, 842, 811, 780, 749, 720,
    690, 662, 634, 606, 580, 553, 528, 503, 478, 455, 431, 409, 387, 365, 344, 324,
    305, 286, 267, 249, 232, 216, 200, 184, 170, 155, 142, 129, 117, 105, 94, 83,
    74, 64, 56, 48, 40, 33, 27, 22, 17, 13, 9, 6, 3, 1, 0, 0,
};

static const Ipp16s ipa_hann_window_short[256] = {
    1, 11, 30, 60, 99, 149, 208, 276, 355, 443, 541, 648, 765, 891, 1026, 1171,
    1325, 1488, 1660, 1840, 2030, 2228, 2435, 2650, 2873, 3105, 3345, 3592, 3847, 4110, 4380, 4657,
    4941, 5233, 5530, 5835, 6146, 6463, 6786, 7115, 7449, 7789, 8134, 8483, 8838, 9197, 9561, 9928,
    10300, 10675, 11054, 11435, 11820, 12208, 12598, 12990, 13385, 13781, 14179, 14578, 14978, 15379, 15780, 16182,
    16585, 16987, 17388, 17789, 18189, 18588, 18986, 19382, 19777, 20169, 20559, 20947, 21332, 21713, 22092, 22467,
    22839, 23206, 23570, 23929, 24284, 24633, 24978, 25318, 25652, 25981, 26304, 26621, 26932, 27237, 27534, 27826,
    28110, 28387, 28657, 28920, 29175, 29422, 29662, 29894, 30117, 30332, 30539, 30737, 30927, 31107, 31279, 31442,
    31596, 31741, 31876, 32002, 32119, 32226, 32324, 32412, 32491, 32559, 32618, 32668, 32707, 32737, 32756, 32766,
    32766, 32756, 32737, 32707, 32668, 32618, 32559, 32491, 32412, 32324, 32226, 32119, 32002, 31876, 31741, 31596,
    31442, 31279, 31107, 30927, 30737, 30539, 30332, 30117, 29894, 29662, 29422, 29175, 28920, 28657, 28387, 28110,
    27826, 27534, 27237, 26932, 26621, 26304, 25981, 25652, 25318, 24978, 24633, 24284, 23929, 23570, 23206, 22839,
    22467, 22092, 21713, 21332, 20947, 20559, 20169, 19777, 19382, 18986, 18588, 18189, 17789, 17388, 16987, 16585,
    16182, 15780, 15379, 14978, 14578, 14179, 13781, 13385, 12990, 12598, 12208, 11820, 11435, 11054, 10675, 10300,
    9928, 9561, 9197, 8838, 8483, 8134, 7789, 7449, 7115, 6786, 6463, 6146, 5835, 5530, 5233, 4941,
    4657, 4380, 4110, 3847, 3592, 3345, 3105, 2873, 2650, 2435, 2228, 2030, 1840, 1660, 1488, 1325,
    1171, 1026, 891, 765, 648, 541, 443, 355, 276, 208, 149, 99, 60, 30, 11, 1,
};

#define FIND_NORM_SHIFT_16S(pSrc, len, shift) \
{                                             \
  Ipp16s _min0, _max0;                        \
  Ipp32s _min, _max;                          \
                                              \
  ippsMinMax_16s(pSrc, len, &_min0, &_max0);  \
                                              \
  _min = -((Ipp32s)_min0);                    \
  _max = _max0;                               \
                                              \
  if (_min > _max) {                          \
    _max = _min - 1;                          \
  }                                           \
                                              \
  shift = 0;                                  \
                                              \
  if (_max > 0) {                             \
    while (_max <= 16383) {                   \
      _max = _max << 1;                       \
      shift++;                                \
    }                                         \
  }                                           \
}

/****************************************************************************/

void mp3ienc_psychoacousticLongWindow(MP3Enc *state,
                                      Ipp16s *input_data,
                                      Ipp32s *rsqr_long,
                                      Ipp32s *rsqr_longScale,
                                      Ipp32s ch)
{
  VM_ALIGN16_DECL(Ipp16s)  sw[N_LONG];
  VM_ALIGN16_DECL(Ipp16s)  abs_sw[N_LONG];
  VM_ALIGN16_DECL(Ipp16s)  fft_line[N_LONG+2];
  VM_ALIGN16_DECL(Ipp32s)  e_b[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp32s)  c_b[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp32s)  ecb[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp32s)  ct[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp32s)  tmp_ecb[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp32s)  tmp_ct[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp32s)  ecb_h_limit[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp32s)  ecb_l_limit[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp32s)  ltmp0[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp16s)  c_w[1024];
  VM_ALIGN16_DECL(Ipp16s)  tmp_ln[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp_ln0[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp_ln1[MAX_PPT_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp0[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp1[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp2[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp3[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp4[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  tmp5[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  denum[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  r_pred[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  re_pred[NUM_UNPRED_LINES_LONG];
  VM_ALIGN16_DECL(Ipp16s)  im_pred[NUM_UNPRED_LINES_LONG];
  Ipp16s *r, *r_prev, *r_prev_prev;
  Ipp16s *re, *re_prev, *re_prev_prev;
  Ipp16s *im, *im_prev, *im_prev_prev;
  Ipp16s *tmp_dst[2];
  Ipp32s *nb,*nb_l;
  Ipp32s b, sb, scaleFactor;
  Ipp32s sum;
  Ipp32s shift0, shift1, shift;
  Ipp32s rScaleFactor, r_prevScaleFactor;
  Ipp32s r_prev_prevScaleFactor, r_predScaleFactor;
  Ipp32s nb_ScaleFactor, nb_lScaleFactor;
  Ipp32s current_f_r_index, prev_f_r_index, prev_prev_f_r_index;
  Ipp32s index;
  Ipp32s pa_num_ptt_long = state->pa_num_ptt_long;
  Ipp32s sum1, sum2;
  Ipp32s freq_ind;

  freq_ind = state->com.header.samplingFreq;

  current_f_r_index = state->ipa_current_f_r_index[ch];
  prev_f_r_index = current_f_r_index - 1;
  if (prev_f_r_index < 0) prev_f_r_index = 2;
  prev_prev_f_r_index = prev_f_r_index - 1;
  if (prev_prev_f_r_index < 0) prev_prev_f_r_index = 2;

  ippsMul_16s_Sfs(input_data, ipa_hann_window_long,
                  sw, state->pa_iblen_long * 2, 15);

  ippsAbs_16s(sw, abs_sw, 2 * state->pa_iblen_long);
  ippsSum_16s32s_Sfs(abs_sw, 2 * state->pa_iblen_long, &sum, 0);

  scaleFactor = 0;
  if (sum != 0) {
    if (sum > 32768) {
      while (sum > 32768) {
        sum >>= 1;
        scaleFactor++;
      }
    } else {
      while (sum <= 16383) {
        sum *= 2;
        scaleFactor--;
      }
    }
  }

  ippsFFTFwd_RToCCS_16s_Sfs(sw, fft_line, state->ipa_pFFTSpecLong,
                            scaleFactor, state->ipa_pBuffer);

  r  = (Ipp16s*)state->ipa_r[ch][current_f_r_index];
  re = (Ipp16s*)state->ipa_re[ch][current_f_r_index];
  im = (Ipp16s*)state->ipa_im[ch][current_f_r_index];

  ippsMagnitude_16sc_Sfs((Ipp16sc *)fft_line, r, state->pa_iblen_long, 1);
  if (ch >= 2)
    ippsSum_16s32s_Sfs(r, 512, &(state->ms_pwr[ch-2]), -(scaleFactor));
  ippsThreshold_LT_16s_I(r, state->pa_iblen_long, 1);

  tmp_dst[0] = re;
  tmp_dst[1] = im;

  ippsDeinterleave_16s(fft_line, 2, NUM_UNPRED_LINES_LONG, tmp_dst);
  ippsDiv_16s_ISfs(r, re, NUM_UNPRED_LINES_LONG, -14);
  ippsDiv_16s_ISfs(r, im, NUM_UNPRED_LINES_LONG, -14);

  FIND_NORM_SHIFT_16S(r, state->pa_iblen_long, shift)
  ippsLShiftC_16s_I(shift, r, state->pa_iblen_long);
  rScaleFactor = scaleFactor + 1 - shift;

  state->ipa_rScaleFactor[ch][current_f_r_index] = rScaleFactor;

  r_prev       = (Ipp16s*)state->ipa_r[ch][prev_f_r_index];
  re_prev      = (Ipp16s*)state->ipa_re[ch][prev_f_r_index];
  im_prev      = (Ipp16s*)state->ipa_im[ch][prev_f_r_index];

  r_prevScaleFactor = state->ipa_rScaleFactor[ch][prev_f_r_index];

  r_prev_prev  = (Ipp16s*)state->ipa_r[ch][prev_prev_f_r_index];
  re_prev_prev = (Ipp16s*)state->ipa_re[ch][prev_prev_f_r_index];
  im_prev_prev = (Ipp16s*)state->ipa_im[ch][prev_prev_f_r_index];

  r_prev_prevScaleFactor = state->ipa_rScaleFactor[ch][prev_prev_f_r_index];

  /* Calculate the unpredictebility measure c(w)                */
  /* Some transformations:                                      */
  /* re((2*r_prev-r_prev_prev)*exp(-j(2*f_prev-f_prev_prev))) = */
  /* (2*r_prev-r_prev_prev)*                                    */
  /* (2*im_prev_prev*re_prev*im_prev +                          */
  /* re_prev_prev*(re_prev*re_prev-im_prev*im_prev))            */
  /*                                                            */
  /* im((2*r_prev-r_prev_prev)*exp(-j(2*f_prev-f_prev_prev))) = */
  /* (2*r_prev-r_prev_prev) *                                   */
  /* (2*re_prev_prev*re_prev*im_prev -                          */
  /* im_prev_prev*(re_prev*re_prev-im_prev*im_prev))            */
  /*                                                            */
  /* where re_prev_prev = cos(prev_prev_f),                     */
  /*       im_prev_prev = sin(prev_prev_f),                     */
  /*       re_prev = cos(prev_prev_f),                          */
  /*       im_prev = sin(prev_prev_f)                           */

  /* r_pred = (2*r_prev-r_prev_prev) */
  r_predScaleFactor = r_prevScaleFactor + 1;
  if (r_prev_prevScaleFactor > r_predScaleFactor) {
    shift = r_prev_prevScaleFactor - r_predScaleFactor;
    if (shift > 16) shift = 16;
    ippsRShiftC_16s(r_prev, shift, tmp0, NUM_UNPRED_LINES_LONG);
    ippsSub_16s_Sfs(r_prev_prev, tmp0, r_pred, NUM_UNPRED_LINES_LONG, 1);
    r_predScaleFactor = r_prev_prevScaleFactor + 1;
  } else if (r_prev_prevScaleFactor < r_predScaleFactor) {
    shift = r_predScaleFactor - r_prev_prevScaleFactor;
    if (shift > 16) shift = 16;
    ippsRShiftC_16s(r_prev_prev, shift, tmp0,NUM_UNPRED_LINES_LONG);
    ippsSub_16s_Sfs(tmp0, r_prev, r_pred, NUM_UNPRED_LINES_LONG, 1);
    r_predScaleFactor++;
  } else {
    ippsSub_16s_Sfs(r_prev_prev, r_prev, r_pred, NUM_UNPRED_LINES_LONG, 1);
    r_predScaleFactor++;
  }

  /* tmp1 = 2*re_prev*im_prev */
  ippsMul_16s_Sfs(re_prev, im_prev, tmp1, NUM_UNPRED_LINES_LONG, 15);

  /* tmp2 = re_prev*re_prev-im_prev*im_prev */
  ippsMul_16s_Sfs(re_prev, re_prev, tmp2, NUM_UNPRED_LINES_LONG, 15);
  ippsMul_16s_Sfs(im_prev, im_prev, tmp, NUM_UNPRED_LINES_LONG, 15);
  ippsSub_16s_ISfs(tmp, tmp2,  NUM_UNPRED_LINES_LONG, 1);

  /* im_prev_prev * tmp1 + re_prev_prev * tmp2 */
  ippsMul_16s_Sfs(im_prev_prev, tmp1, re_pred, NUM_UNPRED_LINES_LONG, 15);
  ippsMul_16s_Sfs(re_prev_prev, tmp2, tmp, NUM_UNPRED_LINES_LONG, 15);
  ippsAdd_16s_ISfs(tmp, re_pred, NUM_UNPRED_LINES_LONG, 1);

  /* re_prev_prev * tmp1 - im_prev_prev * tmp2 */
  ippsMul_16s_Sfs(re_prev_prev, tmp1, im_pred, NUM_UNPRED_LINES_LONG, 15);
  ippsMul_16s_Sfs(im_prev_prev, tmp2, tmp, NUM_UNPRED_LINES_LONG, 15);
  ippsSub_16s_ISfs(tmp, im_pred, NUM_UNPRED_LINES_LONG, 1);

  ippsAbs_16s(r_pred, denum,  NUM_UNPRED_LINES_LONG);

  if (r_predScaleFactor > rScaleFactor) {
    shift0 = 0;
    shift1 = r_predScaleFactor - rScaleFactor;
    if (shift > 16) shift1 = 16;
    ippsRShiftC_16s(r, shift1, tmp0, NUM_UNPRED_LINES_LONG);
    ippsAdd_16s_ISfs(tmp0, denum, NUM_UNPRED_LINES_LONG, 1);
  } else if (r_predScaleFactor < rScaleFactor) {
    shift0 = rScaleFactor - r_predScaleFactor;
    shift1 = 0;
    if (shift0 > 16) shift0 = 16;
    ippsRShiftC_16s(denum, shift0, tmp0, NUM_UNPRED_LINES_LONG);
    ippsAdd_16s_Sfs(r, tmp0, denum, NUM_UNPRED_LINES_LONG, 1);
  } else {
    shift0 = 0;
    shift1 = 0;
    ippsAdd_16s_ISfs(r, denum, NUM_UNPRED_LINES_LONG, 1);
  }

  ippsDiv_16s_Sfs(denum, r_pred, tmp0, NUM_UNPRED_LINES_LONG, -14 + shift0);
  ippsDiv_16s_Sfs(denum, r, tmp1, NUM_UNPRED_LINES_LONG, -14 + shift1);

  ippsMul_16s_Sfs(tmp0, re_pred, tmp2, NUM_UNPRED_LINES_LONG, 15);
  ippsMul_16s_Sfs(tmp0, im_pred, tmp3, NUM_UNPRED_LINES_LONG, 15);
  ippsMul_16s_Sfs(tmp1, re, tmp4, NUM_UNPRED_LINES_LONG, 17);
  ippsMul_16s_Sfs(tmp1, im, tmp5, NUM_UNPRED_LINES_LONG, 17);
  ippsSub_16s_Sfs(tmp2, tmp4, tmp0, NUM_UNPRED_LINES_LONG, 1);
  ippsSub_16s_Sfs(tmp3, tmp5, tmp1, NUM_UNPRED_LINES_LONG, 1);
  ippsMagnitude_16s_Sfs(tmp0, tmp1, c_w, NUM_UNPRED_LINES_LONG, -3);

  ippsSet_16s(13107, &c_w[ NUM_UNPRED_LINES_LONG],
              state->pa_iblen_long -  NUM_UNPRED_LINES_LONG);

  ippsMul_16s32s_Sfs((Ipp16s*)r, (Ipp16s*)r, rsqr_long, state->pa_iblen_long, 0);
  rsqr_longScale[0] = 2 * rScaleFactor;

  index = 0;
  for (b = 0; b < pa_num_ptt_long; b++) {
    Ipp32s *tmp_rsqr = &rsqr_long[index];
    Ipp16s *tmp_c_w = (Ipp16s*)&c_w[index];
    Ipp32s len = mp3ienc_pa_numlines_l[state->com.header.samplingFreq][b];

    ippsSum_32s_Sfs(tmp_rsqr, len, &e_b[b], state->ipa_longScale - 2);
    ippsDotProd_16s32s32s_Sfs(tmp_c_w, tmp_rsqr, len,
                              &c_b[b], state->ipa_longScale + 13);
    index += len;
  }

  nb   = (Ipp32s *)state->ipa_nb_long[ch][state->ipa_nb_curr_index[ch]];
  nb_l = (Ipp32s *)state->ipa_nb_long[ch][state->ipa_nb_prev_index[ch]];

  state->ipa_next_frame_PE[ch] = 0;

  for (b = 0; b < pa_num_ptt_long; b++) {
    Ipp16s *tmp_ptr = (Ipp16s*)state->ipa_sprdngf_long +
                               b * pa_num_ptt_long;

    ippsDotProd_16s32s32s_Sfs(tmp_ptr, e_b, pa_num_ptt_long, &ecb[b], 15);
    ippsDotProd_16s32s32s_Sfs(tmp_ptr, c_b, pa_num_ptt_long, &ct[b], 15);
  }

  ippsMulC_32s_Sfs(ecb, 20219, tmp_ecb, pa_num_ptt_long, 21);
  ippsMulC_32s_Sfs(ct, 17131, tmp_ct, pa_num_ptt_long, 15);

  ippsAdd_32s_Sfs(tmp_ct, tmp_ecb, nb, pa_num_ptt_long, 0);
  ippsMulC_32s_Sfs(ecb, 16462, ecb_h_limit, pa_num_ptt_long, 16);
  ippsMulC_32s_Sfs(ecb, 16619, ecb_l_limit, pa_num_ptt_long, 20);
  ippsMaxEvery_32s_I(ecb_l_limit, nb, pa_num_ptt_long);
  ippsMinEvery_32s_I(ecb_h_limit, nb, pa_num_ptt_long);

  /* instead of nb[b] = MAX( pow(10.0,pBlock->qsthr_long[b]/10.0)/32767.0, */
  /*                         MIN(nb[b],2.0*nb_l[b]));                      */
  /* we use only nb[b] = MIN(nb[b],2.0*nb_l[b]) yet                        */

  nb_ScaleFactor = rsqr_longScale[0] + state->ipa_longScale - 1;
  nb_lScaleFactor = state->ipa_nb_longScaleFactor[ch];

  nb_lScaleFactor += 1;
  if (nb_lScaleFactor > nb_ScaleFactor) {
    shift = nb_lScaleFactor - nb_ScaleFactor;
    /* I use MulC here because LShiftC doesn't provide saturation */
    ippsMulC_32s_ISfs(1, nb_l, pa_num_ptt_long, -shift);
    ippsMinEvery_32s_I(nb_l, nb, pa_num_ptt_long);
    ippsLn_32s16s_Sfs(nb, tmp_ln0, pa_num_ptt_long, -10);
  } else if (nb_lScaleFactor < nb_ScaleFactor) {
    shift = nb_ScaleFactor - nb_lScaleFactor;
    if (shift > 31) shift = 31;
    /* I use MulC here because LShiftC doesn't provide saturation */
    ippsMulC_32s_ISfs(1, nb, pa_num_ptt_long, -shift);
    ippsMinEvery_32s_I(nb_l, nb, pa_num_ptt_long);
    ippsRShiftC_32s(nb, shift, ltmp0, pa_num_ptt_long);
    ippsLn_32s16s_Sfs(ltmp0, tmp_ln0, pa_num_ptt_long, -10);
    nb_ScaleFactor = nb_lScaleFactor;
  } else {
    ippsMinEvery_32s_I(nb_l, nb, pa_num_ptt_long);
    ippsLn_32s16s_Sfs(nb, tmp_ln0, pa_num_ptt_long, -10);
  }

  state->ipa_nb_longScaleFactor[ch] = nb_ScaleFactor;

  ippsLn_32s16s_Sfs(e_b, tmp_ln1, pa_num_ptt_long, -10);
  ippsSub_16s_Sfs(tmp_ln0, tmp_ln1, tmp_ln, pa_num_ptt_long, 1);
  FIND_NORM_SHIFT_16S(tmp_ln, pa_num_ptt_long, shift)
  ippsMul_16s_ISfs(mp3ienc_pa_numlines_l[state->com.header.samplingFreq], tmp_ln, pa_num_ptt_long,
                   state->ipa_longScale - shift);
  ippsSum_16s32s_Sfs(tmp_ln, pa_num_ptt_long, &state->ipa_next_frame_PE[ch],
                     9 - state->ipa_longScale + shift);

  if (state->com.ns_mode) {
    for ( sb = 0; sb < SBBND_L; sb++ ) {
      sum1 = MUL32_MP3_32S(mp3ienc_p2sb_l[freq_ind][sb].w1, e_b[mp3ienc_p2sb_l[freq_ind][sb].bu]);
      sum1 += MUL32_MP3_32S(mp3ienc_p2sb_l[freq_ind][sb].w2, e_b[mp3ienc_p2sb_l[freq_ind][sb].bo]);

      sum2 = MUL32_MP3_32S(mp3ienc_p2sb_l[freq_ind][sb].w1, nb[mp3ienc_p2sb_l[freq_ind][sb].bu]);
      sum2 += MUL32_MP3_32S(mp3ienc_p2sb_l[freq_ind][sb].w2, nb[mp3ienc_p2sb_l[freq_ind][sb].bo]);

      for ( b = mp3ienc_p2sb_l[freq_ind][sb].bu+1; b < mp3ienc_p2sb_l[freq_ind][sb].bo; b++ ) {
        sum1 += e_b[b] >> 3;
        sum2 += nb[b] >> 3;
      }

      if (sum1 > 0)
        ippsDiv_32s_Sfs(&sum1, &sum2, &state->pa_ratio_l_next[ch][sb], 1, -23);
      else
        state->pa_ratio_l_next[ch][sb] = 0;
    }
  }
}

/****************************************************************************/

void mp3ienc_psychoacousticShortWindow(MP3Enc *state,
                                       Ipp16s *input_data,
                                       Ipp32s *s_en,
                                       Ipp32s ch)
{
  VM_ALIGN16_DECL(Ipp16s) sw_short[3][N_SHORT];
  VM_ALIGN16_DECL(Ipp16s) abs_sw[N_SHORT];
  VM_ALIGN16_DECL(Ipp16s) fft_line[N_SHORT+2];
  Ipp32s eb[MAX_PPT_SHORT];
  Ipp32s thr[MAX_PPT_SHORT];
  Ipp16s *ptr_input_data;
  Ipp16s *r;
  Ipp32s win_counter;
  Ipp32s scaleFactor[8], shift;
  Ipp32s min_shift, maxScaleFactor;
  Ipp32s sum, sum1, sum2;
  Ipp32s pa_num_ptt_short = state->pa_num_ptt_short;
  Ipp32s freq_ind;
  Ipp32s j, b, sb;

  freq_ind = state->com.header.samplingFreq;

  ptr_input_data = input_data;

  for (win_counter = 0; win_counter < 3; win_counter++) {
    ptr_input_data += 192;
    ippsMul_16s_Sfs(ptr_input_data, ipa_hann_window_short,
                    sw_short[win_counter],
                    2 * state->pa_iblen_short, 15);
  }

  min_shift = 100;
  maxScaleFactor = -100;

  for (win_counter = 0; win_counter < 3; win_counter++) {
    ippsAbs_16s(sw_short[win_counter], abs_sw, 2 * state->pa_iblen_short);
    ippsSum_16s32s_Sfs(abs_sw, 2 * state->pa_iblen_short, &sum, 0);

    scaleFactor[win_counter] = 0;
    if (sum != 0) {
      if (sum > 32768) {
        while (sum > 32768) {
          sum >>= 1;
          scaleFactor[win_counter]++;
        }
      } else {
        while (sum <= 16383) {
          sum *= 2;
          scaleFactor[win_counter]--;
        }
      }
    }

    ippsFFTFwd_RToCCS_16s_Sfs(sw_short[win_counter],
                              fft_line, state->ipa_pFFTSpecShort,
                              scaleFactor[win_counter],
                              state->ipa_pBuffer);

    r = (Ipp16s*)state->ipa_r_short[ch][state->ipa_current_f_r_index[ch]][win_counter];

    ippsMagnitude_16sc_Sfs((Ipp16sc *)fft_line, r, state->pa_iblen_short, 1);
    ippsThreshold_LT_16s_I(r, state->pa_iblen_short, 1);
    FIND_NORM_SHIFT_16S(&r[(state->pa_iblen_short >> 2)],
                        state->pa_iblen_short - (state->pa_iblen_short >> 2),
                        shift)
    if (min_shift > shift) min_shift = shift;
    if (maxScaleFactor < scaleFactor[win_counter])
      maxScaleFactor = scaleFactor[win_counter];
  }

  for (win_counter = 0; win_counter < 3; win_counter++) {

    r = (Ipp16s*)state->ipa_r_short[ch][state->ipa_current_f_r_index[ch]][win_counter];

    /* The scalefactor 12 - (2*shift+1) is calculated from max value to multiplay. */
    /* This value less than                                                        */
    /* (pBlock->iblen_short - (pBlock->iblen_short >> 2)) * 25 < 96 * 25 = 2400    */
    /* The value 25 is used in comparison (Psychoacoustic module)                  */
    ippsDotProd_16s32s_Sfs(&r[(state->pa_iblen_short >> 2)],
      &r[(state->pa_iblen_short >> 2)],
      state->pa_iblen_short - (state->pa_iblen_short >> 2),
      &s_en[win_counter],
      12 + 2 * (maxScaleFactor- scaleFactor[win_counter])
      - (2*min_shift+1));

    if (state->com.ns_mode) {
      for ( j=0, b = 0; b < pa_num_ptt_short; b++ ) {
        Ipp32s tp = mp3ienc_ptbl_s[freq_ind][b].numlines;

        ippsDotProd_16s32s_Sfs(&r[j], &r[j], tp, &eb[b],
          12 + 2 * (maxScaleFactor- scaleFactor[win_counter])
          - (2*min_shift+1));
        j += tp;
      }

      for ( b = 0; b < pa_num_ptt_short; b++ ){
        Ipp32s ecb, nb;
        Ipp16s *tmp_ptr = (Ipp16s*)state->ipa_sprdngf_short + b * pa_num_ptt_short;
        ippsDotProd_16s32s32s_Sfs(tmp_ptr, eb, pa_num_ptt_short, &ecb, 15);

        nb = MUL32_MP3_32S(ecb, mp3ienc_ptbl_s[freq_ind][b].SNR);
        thr[b] = IPP_MAX(mp3ienc_ptbl_s[freq_ind][b].qthr,nb);
      }
      for ( sb = 0; sb < SBBND_S; sb++ ) {
        sum1 = MUL32_MP3_32S(mp3ienc_p2sb_s[freq_ind][sb].w1, eb[mp3ienc_p2sb_s[freq_ind][sb].bu]);
        sum1 += MUL32_MP3_32S(mp3ienc_p2sb_s[freq_ind][sb].w2, eb[mp3ienc_p2sb_s[freq_ind][sb].bo]);

        sum2 = MUL32_MP3_32S(mp3ienc_p2sb_s[freq_ind][sb].w1, thr[mp3ienc_p2sb_s[freq_ind][sb].bu]);
        sum2 += MUL32_MP3_32S(mp3ienc_p2sb_s[freq_ind][sb].w2, thr[mp3ienc_p2sb_s[freq_ind][sb].bo]);

        for ( b = mp3ienc_p2sb_s[freq_ind][sb].bu+1; b < mp3ienc_p2sb_s[freq_ind][sb].bo; b++ ) {
          sum1 += eb[b] >> 3;
          sum2 += thr[b] >> 3;
        }

        if (sum1 > 0)
          ippsDiv_32s_Sfs(&sum1, &sum2, &state->pa_ratio_s_next[ch][win_counter][sb], 1, -23);
        else
          state->pa_ratio_s_next[ch][win_counter][sb] = 0;
      }
    }
  }
}

/****************************************************************************/

Ipp32s mp3ienc_psychoacousticInit(MP3Enc *state, Ipp8u *mem, Ipp32s *size_all)
{
  Ipp32s i, j, gr, ch;
  Ipp32s max_len;
  Ipp32s num_ptt, b, bb;
  const Ipp32s num_ptt_long_tbl[3] = {63,62,59};
  const Ipp32s num_ptt_short_tbl[3] = {39,38,42};
  Ipp32s freq_ind;
  const Ipp16s *bval;
  Ipp16s *sprdngf;
  Ipp32s jj;
  Ipp32s size, ts, ts1, size_buf, size_init, size_buf1, size_init1;
  Ipp8u *mem_init;

  size = 0;

  ippsFFTGetSize_R_16s(10, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast, &ts, &size_init, &size_buf);
  ippsFFTGetSize_R_16s(8, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast, &ts1, &size_init1, &size_buf1);
  if (size_buf < size_buf1) size_buf = size_buf1;
  if (size_init < size_init1) size_init = size_init1;

  size += ts + ts1 + size_buf;

  if (mem) {
    mem_init = 0;
    if (size_init) {
      mem_init = ippsMalloc_8u(size_init);
      if (!mem_init)
        return MP3_ALLOC;
    }

    ippsFFTInit_R_16s(&(state->ipa_pFFTSpecLong), 10, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast, mem, mem_init);
    mem += ts;
    ippsFFTInit_R_16s(&(state->ipa_pFFTSpecShort), 8, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast, mem, mem_init);
    mem += ts1;
    state->ipa_pBuffer = mem;
    mem += size_buf;
    if(mem_init)
      ippsFree(mem_init);
  }

  /*
  if (ippsFFTInitAlloc_R_16s(&(state->ipa_pFFTSpecLong),
  10, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast) != ippStsOk)
  return 1;

  if (ippsFFTInitAlloc_R_16s(&(state->ipa_pFFTSpecShort),
  8, IPP_FFT_NODIV_BY_ANY, ippAlgHintFast)  != ippStsOk)
  return 1;

  if (ippsFFTGetBufSize_R_16s(state->ipa_pFFTSpecLong, &size) != ippStsOk)
  return 1;

  if (ippsFFTGetBufSize_R_16s(state->ipa_pFFTSpecShort, &size_short) != ippStsOk)
  return 1;

  if (size < size_short) size = size_short;

  if (size != 0) {
  state->ipa_pBuffer = ippsMalloc_8u(size);
  if (state->ipa_pBuffer == NULL)
  return 1;
  }
  */

  if(state) {
    freq_ind = state->com.header.samplingFreq;

    state->ms_dcoef[0] = state->ms_dcoef[1] = state->ms_dcoef_next = 0;
    state->ms_ncoef[0] = state->ms_ncoef[1] = state->ms_ncoef_next = 0;
    state->pa_iblen_long  = 512;
    state->pa_iblen_short = 128;

    for (ch = 0; ch < 4; ch++)
      state->ipa_current_f_r_index[ch] = 2;

    for (ch = 0; ch < 4; ch++) {
      state->ipa_desired_block_type[ch] = NORM_TYPE;
      for (gr = 0; gr < 2; gr++)
      state->ipa_next_desired_block_type[gr][ch] = NORM_TYPE;
    }

    state->pa_num_ptt_long = num_ptt = num_ptt_long_tbl[freq_ind];

    bval = mp3ienc_bval_l[freq_ind];
    sprdngf = (Ipp16s*)state->ipa_sprdngf_long;

    for (jj = 0; jj < 1; jj++) {

      for (b = 0; b < num_ptt; b++) {
        Ipp16s *tmp_ptr = sprdngf + b * num_ptt;
        Ipp32s tmp = 0;
        Ipp32s scalef = -15;
        Ipp16s src2 = bval[b];

        for (bb = 0; bb < num_ptt; bb++) {
          ippsSpread_16s_Sfs(bval[bb], src2, -10, tmp_ptr + bb);
          tmp += tmp_ptr[bb];
        }

        while (tmp >= 32768) {
          scalef += 1;
          tmp >>= 1;
        }

        ippsDivC_16s_ISfs((Ipp16s)tmp, tmp_ptr, num_ptt, scalef);
      }
    }

    state->pa_num_ptt_short = num_ptt = num_ptt_short_tbl[freq_ind];

    sprdngf = (Ipp16s*)state->ipa_sprdngf_short;

    for (jj = 0; jj < 1; jj++) {
      for (b = 0; b < num_ptt; b++) {
        Ipp16s *tmp_ptr = sprdngf + b * num_ptt;
        Ipp32s tmp = 0;
        Ipp32s scalef = -15;
        Ipp16s src2 = mp3ienc_ptbl_s[freq_ind][b].bval;

        for (bb = 0; bb < num_ptt; bb++) {
          ippsSpread_16s_Sfs(mp3ienc_ptbl_s[freq_ind][bb].bval,
            src2, -10, tmp_ptr + bb);
          tmp += tmp_ptr[bb];
        }

        while (tmp >= 32768) {
          scalef += 1;
          tmp >>= 1;
        }

        ippsDivC_16s_ISfs((Ipp16s)tmp, tmp_ptr, num_ptt, scalef);
      }
    }

    for (ch = 0; ch < 4; ch++) {
      state->ipa_nb_curr_index[ch] = 1;
      state->ipa_nb_prev_index[ch] = 0;
    }

    max_len = 0;
    for (i = 0; i < state->pa_num_ptt_long; i++) {
      Ipp32s len = mp3ienc_pa_numlines_l[freq_ind][i];
      if (len > max_len) max_len = len;
    }

    state->ipa_longScale = 0;
    while (max_len > (1 << state->ipa_longScale)) {
      state->ipa_longScale++;
    }

    max_len = 0;
    for (i = 0; i < state->pa_num_ptt_short; i++) {
      Ipp32s len = mp3ienc_ptbl_s[freq_ind][i].numlines;
      if (len > max_len) max_len = len;
    }

    state->ipa_shortScale = 0;
    while (max_len > (1 << state->ipa_shortScale)) {
      state->ipa_shortScale++;
    }

    for (ch = 0; ch < 4; ch++)
    for (i = 0; i < MAX_PPT_LONG; i++) {
      for (j = 0; j < 3; j++)
      state->ipa_nb_long[ch][j][i] = 0x7FFFFFFF;
    }

    state->ipa_nb_longScaleFactor[0] = 0x7FFFFFF;
    state->ipa_nb_longScaleFactor[1] = 0x7FFFFFF;

    for (ch = 0; ch < 4; ch++)
    for (i = 0; i < 512; i++) {
      state->ipa_r[ch][0][i] = state->ipa_r[ch][1][i] = state->ipa_r[ch][2][i] = 1;
      state->ipa_re[ch][0][i] = state->ipa_re[ch][1][i] = state->ipa_re[ch][2][i] = 1;
      state->ipa_im[ch][0][i] = state->ipa_im[ch][1][i] = state->ipa_im[ch][2][i] = 0;
    }

    for (ch = 0; ch < 4; ch++)
    for (j = 0; j < 3; j++) {
      for (i = 0; i < 128; i++) {
        state->ipa_r_short[ch][0][j][i] = state->ipa_r_short[ch][1][j][i] =
        state->ipa_r_short[ch][2][j][i] = 1;

        state->ipa_re_short[ch][0][j][i] = state->ipa_re_short[ch][1][j][i] =
        state->ipa_re_short[ch][2][j][i] = 1;

        state->ipa_im_short[ch][0][j][i] = state->ipa_im_short[ch][1][j][i] =
        state->ipa_im_short[ch][2][j][i] = 0;
      }
    }

    for (ch = 0; ch < 4; ch++)
      state->ipa_next_frame_PE[ch] = 0;
  }

  if(size_all)
    *size_all = size;

  return 0;
}

/****************************************************************************/

void mp3ienc_psychoacousticFree(MP3Enc *state)
{
    if (state->ipa_pFFTSpecShort)
      ippsFFTFree_R_16s(state->ipa_pFFTSpecShort);

    if (state->ipa_pFFTSpecLong)
      ippsFFTFree_R_16s(state->ipa_pFFTSpecLong);

    if (state->ipa_pBuffer)
      ippsFree(state->ipa_pBuffer);
}

/****************************************************************************/

static void mp3ienc_psychoacoustic_stage1(MP3Enc *state, Ipp16s *pa_buffer, Ipp32s gr, Ipp32s ch)
{
  VM_ALIGN16_DECL(Ipp32s) rsqr_long[1024];
  Ipp32s s_en[3];
  Ipp32s min, max;
  Ipp32s rsqr_longScale;
  Ipp32s i, j;

  state->ipa_curr_frame_PE_st[gr][ch] =
  state->ipa_curr_frame_PE[ch] = state->ipa_next_frame_PE[ch];

  for (i = 0; i < SBBND_L; i++)
    state->pa_ratio_l[gr][ch][i] = state->pa_ratio_l_next[ch][i];

  for (j = 0; j < 3; j++)
    for (i = 0; i < SBBND_S; i++)
      state->pa_ratio_s[gr][ch][j][i] = state->pa_ratio_s_next[ch][j][i];

  mp3ienc_psychoacousticLongWindow(state, pa_buffer, rsqr_long, &rsqr_longScale, ch);
  mp3ienc_psychoacousticShortWindow(state, pa_buffer, s_en, ch);

  ippsMinMax_32s(s_en, 3, &min, &max);

  /* part 1 */

  if (state->ipa_next_frame_PE[ch] > 2900) {
    state->ipa_next_desired_block_type[gr][ch] = SHORT_TYPE;
  } else if (max > 20 * min) {
    state->ipa_next_desired_block_type[gr][ch] = SHORT_TYPE;
  } else if ((max > 10 * min) && (state->ipa_next_frame_PE[ch] > 1500)) {
    state->ipa_next_desired_block_type[gr][ch] = SHORT_TYPE;
  } else {
    state->ipa_next_desired_block_type[gr][ch] = NORM_TYPE;
  }

  state->ipa_current_f_r_index[ch]++;
  if (state->ipa_current_f_r_index[ch] >= 3)
    state->ipa_current_f_r_index[ch] = 0;

  state->ipa_nb_curr_index[ch] ^= 1;
  state->ipa_nb_prev_index[ch] ^= 1;
}

void mp3ienc_psychoacoustic(MP3Enc *state, Ipp16s **pa_buffer)
{
  Ipp32s gr, ch, ms, stereo;

  stereo = state->com.stereo;

  for (gr = 0; gr < 2; gr++) {
    for (ch = 0; ch < stereo; ch++)
      mp3ienc_psychoacoustic_stage1(state, pa_buffer[ch] + gr * 576, gr, ch);

    if (state->com.stereo_mode_param == MPA_MS_STEREO ||
      state->com.stereo_mode_param == MPA_JOINT_STEREO) {
        for (ch = 2; ch < 4; ch++)
          mp3ienc_psychoacoustic_stage1(state, pa_buffer[ch] + gr * 576, gr, ch);

        state->ms_ncoef[gr] = state->ms_ncoef_next;
        state->ms_dcoef[gr] = state->ms_dcoef_next;
        state->ms_ncoef_next = state->ms_pwr[0];
        state->ms_dcoef_next = state->ms_pwr[0] + state->ms_pwr[1];
      }
  }

  state->com.stereo_mode = state->com.stereo_mode_param;

  if (state->com.stereo_mode_param == MPA_JOINT_STEREO) {
    if (((state->ipa_curr_frame_PE_st[0][2] + state->ipa_curr_frame_PE_st[0][3] +
      state->ipa_curr_frame_PE_st[1][2] + state->ipa_curr_frame_PE_st[1][3]) << 2) <
      3 * (state->ipa_curr_frame_PE_st[0][0] + state->ipa_curr_frame_PE_st[0][1] +
      state->ipa_curr_frame_PE_st[1][0] + state->ipa_curr_frame_PE_st[1][1]) ||
      ((state->ms_ncoef[0] << 2) > 3 * state->ms_dcoef[0] && (state->ms_ncoef[1] << 2) > 3 * state->ms_dcoef[1]))
      state->com.stereo_mode = MPA_MS_STEREO;
    else
      state->com.stereo_mode = MPA_LR_STEREO;
  }

  if(state->com.stereo_mode_param == MPA_JOINT_STEREO ||
    state->com.stereo_mode_param == MPA_MS_STEREO) {
      for(ch = 0; ch <= 2; ch += 2) {
        for (gr = 0; gr < 2; gr++) {
          if ( state->ipa_next_desired_block_type[gr][ch] != state->ipa_next_desired_block_type[gr][ch+1])
            state->ipa_next_desired_block_type[gr][ch] =
            state->ipa_next_desired_block_type[gr][ch+1] = SHORT_TYPE;
        }
      }
    }

    ms = state->com.stereo_mode == MPA_MS_STEREO ? 2 : 0;

    for (gr = 0; gr < 2; gr++) {
      for (ch = 0; ch < state->com.stereo; ch++) {
        Ipp32s next_desired_block_type = state->ipa_next_desired_block_type[gr][ch+ms];
        if (next_desired_block_type == NORM_TYPE) {
          if (state->ipa_desired_block_type[ch] == SHORT_TYPE)
            next_desired_block_type = STOP_TYPE;
        } else {
          if (state->ipa_desired_block_type[ch] == NORM_TYPE )
            state->ipa_desired_block_type[ch] = START_TYPE;
          if ( state->ipa_desired_block_type[ch] == STOP_TYPE ) {
            state->ipa_desired_block_type[ch] = SHORT_TYPE;
          }
        }

        state->com.si_blockType[gr][ch] = state->ipa_desired_block_type[ch];
        state->ipa_desired_block_type[ch] = next_desired_block_type;

        if ((mp3_bitrate[state->com.header.id][state->com.header.layer-1]
              [state->com.header.bitRate] >> (state->com.stereo - 1)) <= 40)
          state->com.si_blockType[gr][ch] = NORM_TYPE;

        if (state->com.si_blockType[gr][ch] == NORM_TYPE)
          state->com.si_winSwitch[gr][ch] = 0;
        else
          state->com.si_winSwitch[gr][ch] = 1;

        state->com.si_mixedBlock[gr][ch] = 0;
      }
    }
}

/****************************************************************************/

#endif //UMC_ENABLE_MP3_INT_AUDIO_ENCODER
